#pragma once
#include "fileds.hpp"
#include <memory>
#include <functional>

namespace rpc
{
    class BaseMessage
    {
    public:
        using ptr = std::shared_ptr<BaseMessage>;
        // 消息析造函数抽象
        virtual ~BaseMessage()
        {
        }
        // 设置消息类型
        virtual void setMytype(const MY_TYPE &type)
        {
            _type = type;
        }
        // 获得消息类型
        virtual MY_TYPE getMytype()
        {
            return _type;
        }
        // 设置消息id
        virtual void setId(const std::string &id)
        {
            _rid = id;
        }
        // 获得消息id
        virtual std::string getId()
        {
            return _rid;
        }
        // 序列化+反序列化+校验
        virtual std::string serilize() = 0;
        virtual bool unserilize(const std::string &msg) = 0;
        virtual bool check() = 0;

    private:
        MY_TYPE _type;    // 消息类型
        std::string _rid; // 消息id
    };

    // 缓冲区的抽象
    class BaseBuffer
    {
    public:
        using ptr = std::shared_ptr<BaseBuffer>;
        // 返回缓冲区中能读取的大小
        virtual size_t readAbleSiae() = 0;
        // 读取4个字节的内存大小
        virtual int32_t peekInt32() = 0;
        // 删除四个字节大小
        virtual void retriveInt32() = 0;
        // 读取并删除
        virtual int32_t readInt32() = 0;
        // 读取指定长度的缓存并转化为string类型
        virtual std::string retriveAsString(size_t len) = 0;
    };

    // 协议层处理：判断是否能够处理  转换成协议类型   返回消息。要从缓存取数据
    class BaseProtocol
    {
    public:
        using ptr = std::shared_ptr<BaseProtocol>;
        // 判断能否处理
        virtual bool canProcessed(const BaseBuffer::ptr &buff) = 0;
        // 序列化消息：要按照协议序列化,序列化后返回一个字符串
        virtual std::string searilize(const BaseMessage::ptr &msg) = 0;
        // 处理消息，还给一个消息
        virtual bool onMessage(const BaseBuffer::ptr &buff, BaseMessage::ptr &msg) = 0;
    };

    // 连接层抽象：按照协议层将数据转换为对应的格式后便发送数据
    class BaseConnection
    {
    public:
        using ptr = std::shared_ptr<BaseConnection>;
        // 发送消息
        virtual bool send(const BaseMessage::ptr &msg) = 0;
        // 判断是否建立连接
        virtual bool connect() = 0;
        // 关闭连接
        virtual void disConnect() = 0;
    };

    // 服务端抽象：实现连接，关闭，消息回调的设置。以及启动的设计------设置好回调后启动服务器
    using ConnectionCallback = std::function<void(const BaseConnection::ptr &)>;
    using CloseCallback = std::function<void(const BaseConnection::ptr &)>;
    using MessageCallback = std::function<void(const BaseConnection::ptr &, BaseMessage::ptr &)>;
    class BaseServer
    {
    public:
        using ptr = std::shared_ptr<BaseServer>;
        // 设置连接回调
        virtual void setConnectionCallback(const ConnectionCallback &cb)
        {
            _cb_connection = cb;
        }
        // 设置关闭回调
        virtual void setCloseCallback(const CloseCallback &cb)
        {
            _cb_close = cb;
        }
        // 设置消息回调
        virtual void setMessageCallback( const MessageCallback& cb)
        {
            _cb_message = cb;
        }
        // 设置启动函数，如何启动就由使用者决定
        virtual void start() = 0;

    protected:
        ConnectionCallback _cb_connection;
        CloseCallback _cb_close;
        MessageCallback _cb_message;
    };

    // 设置服务端抽象:设置好回调+连接+关闭+是否连接正常+发送消息
    class BaseClient
    {
    public:
        using ptr = std::shared_ptr<BaseClient>;
        // 设置连接回调
        virtual void setConnectionCallback(const ConnectionCallback &cb)
        {
            _cb_connection = cb;
        }
        // 设置关闭回调
        virtual void setCloseCallback(const CloseCallback &cb)
        {
            _cb_close = cb;
        }
        // 设置消息回调
        virtual void setMessageCallback(const MessageCallback &cb)
        {
            _cb_message = cb;
        }
        // 连接函数
        virtual void connect() = 0;
        // 关闭函数
        virtual void shutdown() = 0;
        // 判断连接是否正常
        virtual bool connected() = 0;
        // 发送数据
        virtual bool send(const BaseMessage::ptr &msg) = 0;
        // 获取连接对象
        virtual BaseConnection::ptr connection() = 0;

    protected:
        ConnectionCallback _cb_connection;
        CloseCallback _cb_close;
        MessageCallback _cb_message;
    };
}